// Copyright (c) 2010, Anthony Cassidy
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are 
// permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, this list 
//         of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//         list of conditions and the following disclaimer in the documentation and/or 
//         other materials provided with the distribution.
//     * Neither the name of the AntsAdventureGameCreator nor the names of its contributors 
//         may be used to endorse or promote products derived from this software without 
//         specific prior written permission.
// 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.
#include "XStdafx.h"
#include "XImage.h"

XImage::XImage()
: m_x(0)
, m_y(0)
{
}

XImage::~XImage()
{
}

QRect XImage::Rect()
{ 
    return QRect(m_x, m_y, m_image.width(), m_image.height()); 
}
   

void XImage::DrawImage(QPainter& displayPainter, int x, int y)
{
    //just draw teh cropped image at its internal coords + the x,y past in
    displayPainter.drawImage(x+m_x, y+m_y, m_image);
    // TODO, add this debugging feature as a menu option: displayPainter.drawRect(QRect(x+m_x,y+m_y, m_image.width(),m_image.height())); 
}

void XImage::DrawZBuffer(QPainter& zbufferPainter, int x, int y)
{
    // just draw the croped image at its internal coords + the x,y past in
    zbufferPainter.drawImage(x+m_x, y+m_y, m_zbuf);
}

QImage GenerateZBufferRepresentation(QImage image, QRgb zbufferColor)
{
    QImage zbuf = image.createHeuristicMask(false);
    zbuf.invertPixels();
    QImage alphed(zbuf.width(), zbuf.height(), QImage::Format_ARGB32_Premultiplied);
    alphed.fill(zbufferColor);// if aplha, then fill will overwrite alpha
    alphed.setAlphaChannel(zbuf);
    return alphed;
}

QRect GetBoundingNonBlackRectangle(QImage image)
{
    int max = image.width() > image.height()? image.width() : image.height();
    int top = 0;
    int left = 0;
    int bottom = image.height()-1;
    int right = image.width()-1;
    bool isToKeepAdvancingTop = true;
    bool isToKeepAdvancingLeft = true;
    bool isToKeepAdvancingBottom = true;
    bool isToKeepAdvancingRight = true;
    // this turns off the optimization :return QRect(QPoint(left,top),QPoint(right,bottom));

    // This is finding the bounding box by keeping shrinking the square (top,left,bottom,right)
    // until it runs into some non zero pixels.
    // we alternate between vertical and horizontal, because overall, this results in
    // fewer pixels to scan ( every horizontal line scanned can be two pixels shorter than the previous)
    for(int i=0;i<max;i++)
    {
        for(int k=left;k<=right && (isToKeepAdvancingTop || isToKeepAdvancingBottom);k++)
        {
            int colorTop = image.pixel(k,top)&RGB_MASK;
            int colorBottom = image.pixel(k,bottom)&RGB_MASK;
            isToKeepAdvancingTop &= (colorTop==0);
            isToKeepAdvancingBottom &= (colorBottom==0);
        }

        top += isToKeepAdvancingTop;
        bottom -= isToKeepAdvancingBottom;

        for(int k=top;k<=bottom && (isToKeepAdvancingLeft || isToKeepAdvancingRight);k++)
        {
            int colorLeft = image.pixel(left,k)&RGB_MASK;
            int colorRight = image.pixel(right,k)&RGB_MASK;
            isToKeepAdvancingRight &= (colorRight==0);
            isToKeepAdvancingLeft &= (colorLeft==0);
        }

        left += isToKeepAdvancingLeft;
        right -= isToKeepAdvancingRight;
    }

    return QRect(QPoint(left,top),QPoint(right,bottom));
}

bool XImage::Load(QString filename, QRgb colorForZBuffer)
{
    QImage temp;
    bool isLoaded = temp.load(filename);

    // we need to set black in all the four corners because of createHeiristicMask
    // which is used in GenerateZBufferRepresentation, this takes a color key from the four corners.
    int x = temp.width()-1;
    int y = temp.height()-1;
    temp.setPixel(x,y,0);
    temp.setPixel(x,0,0);
    temp.setPixel(0,y,0);
    temp.setPixel(0,0,0);

    if(isLoaded)
    {
        QRect rect = GetBoundingNonBlackRectangle(temp);
        m_image = temp.copy(rect.x(), rect.y(), rect.width(), rect.height());
        m_zbuf = GenerateZBufferRepresentation(m_image, colorForZBuffer);
        m_x = rect.x();
        m_y = rect.y();
    }
    return isLoaded;
}

bool XImage::IsNull()
{
    return m_image.isNull();
}

void XImage::DrawDot(QPoint p)
{
    int x = p.x() - m_x;
    int y = p.y() - m_y;
    ASSERT(x>=0);
    ASSERT(y>=0);

    m_image.setPixel(x,y, qRgb(255,0,0));
    m_image.setPixel(x-1,y, qRgb(255,0,0));
    m_image.setPixel(x,y-1, qRgb(255,0,0));
    m_image.setPixel(x-1,y-1, qRgb(255,0,0));
}
